#include "../Epsilon/debug.h"

#include "font.h"
#include "../Epsilon/Epsilon3D/image.h"

#include "../Epsilon/Epsilon3D/OpenGL.h"

#include "../Epsilon/Epsilon3D/rendercontext.h"
#include "../Epsilon/Epsilon3D/immediate.h"
#include "../Epsilon/Epsilon3D/vcache.h"
#include "../Epsilon/Epsilon3D/texture.h"
#include "states.h"
#include "console.h"
#include "window.h"

#include <ft2build.h>
#include FT_FREETYPE_H

#ifdef _MSC_VER
# ifdef _DEBUG
#  pragma comment (lib, "../freetype/lib/freetype244_D.lib")
# else
#  pragma comment (lib, "../freetype/lib/freetype244.lib")
# endif
#endif

/*
#include "FontManager.h"
#include "StringCache.h"
*/

#define MAX_TEX_RES 512

/// Name & location of the fonts logfile on disk
const TCHAR* FONTS_LOG_FILE = _T ("logs/fonts.log");

// The maximum and minimum loaded ascii characters.  More loaded characters means more used
// memory.  Do *not* load all 65535 Unicode characters.  Load a range.  If you are porting to
// a character set where the characters are sparsely distributed, you'll need to change the font
// core code.  If the character set has a large number of glyphs (>500) you should think about
// creating a glyph cache.
/*
const int MIN_LOADED_CHAR = 32;
const int MAX_LOADED_CHAR = 126;
*/

const int MIN_LOADED_CHAR = 32;
const int MAX_LOADED_CHAR = 255;


/// Static instance of the fonts logfile
FILE* eFont::_log = NULL;

/// Trick to close the fonts logfile at GUI termination
eFontStaticsInitializer _staticFontsIntializer;

//&& extern cStringCache stringCache;    // defined in StringCache.cpp



static
int
eNextPowerOf2 (int in)
{
  in -= 1;

  in |= in >> 16;
  in |= in >> 8;
  in |= in >> 4;
  in |= in >> 2;
  in |= in >> 1;

  return in + 1;
}


void
eFont::DecrementRefs (void)
{ 
  Assert (false, _T ("TODO"));

  /*
  if (--refCount <= 0)
    eFontManager::GetInstance ()->FreeFont (this);
  */
}


// PrintToBuffer() writes a text texture representing the string to the given buffer.
// Assumes the buffer is large enough or larger than necessary to contain the string.
// If the buffer is larger, the space at the end of the buffer is left as it is, and
// not overwritten.  The string is assumed to be null terminated.  The buffer does not
// have to be zeroed beforehand - the text pixels will replace what is already there.
// This method only works if the memory font is loaded for this font.
void
eFont::PrintToBuffer (const TCHAR* szString, unsigned char* pBuffer, int bufferWidth) {
  Assert (MemoryFontIsLoaded (), _T ("eFont::PrintToBuffer (...) bad state"))

  int charOffset;
  int charWriteOffset = 0;
  int writeOffset;

  TCHAR c = *szString;

  while (c != 0) {
    if (c > maxChar)
      c = _T (' ');  // prevent array overruns

    // Copy each character over, one by one.  This just copies one 1D region in memory to 
    // a 2D region
    charOffset  = glyphs_ [c].offset;
    writeOffset = charWriteOffset;

    // To optimize this to be more cache friendly we have stored each character linearly in memory
    int advance = glyphs_ [c].advance;
    for (int row = 0; row < bitmap_height_; row++) {
      for (int col = 0; col < advance; col++) {
        pBuffer [writeOffset + col] = bitmap_ [charOffset]; 
        charOffset++;
      }
      writeOffset += bufferWidth;
    }

    charWriteOffset += advance;
    szString++;

    c = *szString;
  }
}


/// Calculates the position to align text within a rectangle
void eFont::TextPos (TCHAR*         szText,          // The text to display
                     ePoint*        pos,            // The position that this function will calculate
                     eGlyphTexRect* rect,            // The rectangle to position the text in
  /*GUI_CONSTANTS::alignment_t alignment,*/       // The alignment of the text within the rectangle
                     int*           numCharsThatFit) // The number of characters that can be rendered without overrunning the rectangle
{ 
  pos->y = CenterVert (rect->GetY (), rect->GetHeight ());

  // Calculate the length & number of characters that fit
  float width    = 0.0f;
  int   numChars = 0;

  TCHAR c = szText [numChars];

  float advance = GetAdvance (c);
  while ((width + advance) < rect->GetWidth () && c != 0) {
    width += advance;
    numChars++;

    c       = szText [numChars];
    advance = GetAdvance (c);
  }
  *numCharsThatFit = numChars;

  pos->x = rect->GetX ();
  /*
  // Align the text horizontally
  if (alignment==GUI_CONSTANTS::Left)
    pos->x = rect->GetX();
  else if (alignment==GUI_CONSTANTS::Center)
    pos->x = rect->GetX() + 0.5f*(rect->GetWidth() - width);
  else if (alignment==GUI_CONSTANTS::Right)
    pos->x = rect->GetX() + rect->GetWidth() - width;
  */
  pos->x = (float)((int)(pos->x));   // Make sure text is aligned to pixel boundaries
}



float
eFont::Print (const TCHAR* string, int numChars, float x, float y)
{
  if (numChars <= 0)
    return x;

  TCHAR c = *string;

  //texture_->Bind (Epsilon3D::Texture::TexUnit0);

  glBegin (GL_QUADS);
    if (c > maxChar)
      c = _T (' ');    // prevent array overruns

    int count = 1;    // number of characters printed so far

    while (c != 0) {
      eGlyphTexRect&   r  = glyphs_ [c].rect;
      eGlyphTexCoords& st = glyphs_ [c].st;

      glTexCoord2f (st.min.u, st.min.v);
      glVertex2f   (x + r.x, y + r.y);

      glTexCoord2f (st.min.u, st.max.v);
      glVertex2f   (x + r.x, y + r.y + r.h);

      glTexCoord2f (st.max.u, st.max.v);
      glVertex2f   (x + r.w + r.x, y + r.y + r.h);

      glTexCoord2f (st.max.u, st.min.v);
      glVertex2f   (x + r.w + r.x, y + r.y);

      x += glyphs_ [c].advance;

      if (count == numChars)
        break;

      count++;
      string++;

      c = *string;

      if (c > maxChar)
        c = _T (' ');    // prevent array overruns
    }
  glEnd ();

  return x;
}

struct GlyphVertex
{
  float         pos   [3];
//  unsigned char color [4];
  float         st    [2];
};

static std::vector<GlyphVertex>    verts;   static int verts_size   = 0;
static std::vector<unsigned short> indices; static int indices_size = 0;

void
AddVertex (GlyphVertex& vert, int num, int incr = 4)
{
  if (verts_size <= num) {
    verts.resize (verts_size + incr);
    verts_size += incr;
  }

  verts [num] = vert;
}

void
AddIndex (unsigned short idx, int num, int incr = 6)
{
  if (indices_size <= num) {
    indices.resize (indices_size + incr);
    indices_size += incr;
  }

  indices [num] = idx;
}


float
eFont::Print (const TCHAR* string, float x, float y, e3dVertexCache* vcache, e3dIndexCache* icache, float scale)
{
  // In OpenGL, we draw from the bottom up, so find the BOTTOM Y coordinate...
  if (scale != 1.0f) {
    y -= (GetRowHeight () * (2.0f / scale));
  } else {
    y -= (GetRowHeight () * 1.25f);
  }

  int num_tris = 0;

  TCHAR c = *string;

  if (c > maxChar)
    c = _T (' ');    // prevent array overruns

  unsigned short vtx_count = 0;
  unsigned int   idx_count = 0;

  while (c != 0) {
    eGlyphTexRect&   r  = glyphs_ [c].rect;
    eGlyphTexCoords& st = glyphs_ [c].st;

    GlyphVertex vert;

    /* These two statements uncommented on 5/27/2011 - Fixes Win32... */
    vert.pos   [2] = 0.0f;
    vert.pos   [3] = 1.0f;

    vert.pos [0] = x + r.x * scale;
    vert.pos [1] = y + r.y * scale;
    vert.st  [0] = st.min.u;
    vert.st  [1] = st.min.v;

    AddVertex (vert, vtx_count);

    vert.pos [0] = x + r.x * scale;
    vert.pos [1] = y + r.y * scale - (r.h * scale);
    vert.st  [0] = st.min.u;
    vert.st  [1] = st.max.v;

    AddVertex (vert, vtx_count + 1);

    vert.pos [0] = x + r.x * scale + (r.w * scale);
    vert.pos [1] = y + r.y * scale - (r.h * scale);
    vert.st  [0] = st.max.u;
    vert.st  [1] = st.max.v;

    AddVertex (vert, vtx_count + 2);

    vert.pos [0] = x + r.x * scale + (r.w * scale);
    vert.pos [1] = y + r.y * scale;
    vert.st  [0] = st.max.u;
    vert.st  [1] = st.min.v;

    AddVertex (vert, vtx_count + 3);


    /*
    icache->Resize (icache->GetSize () + 6);

    icache->SetIndex (last_idx, last_vtx + 0);
    icache->SetIndex (last_idx, last_vtx + 1);
    icache->SetIndex (last_idx, last_vtx + 2);
    icache->SetIndex (last_idx, last_vtx + 0);
    icache->SetIndex (last_idx, last_vtx + 2);
    icache->SetIndex (last_idx, last_vtx + 3);
    */

////    indices.push_back (0); indices.push_back (1); indices.push_back (2);
////    indices.push_back (0); indices.push_back (2); indices.push_back (3);

    AddIndex (vtx_count + 0, idx_count++);
    AddIndex (vtx_count + 1, idx_count++);  /* Triangle #1 */
    AddIndex (vtx_count + 2, idx_count++);

    AddIndex (vtx_count + 0, idx_count++);
    AddIndex (vtx_count + 2, idx_count++);  /* Triangle #2 */
    AddIndex (vtx_count + 3, idx_count++);

    vtx_count += 4;
    num_tris  += 2;

    x += glyphs_ [c].advance;

    string++;
    c = *string;

    if (c > maxChar)
      c = _T (' ');    // prevent array overruns
  }

  glPushAttrib   (GL_TRANSFORM_BIT | GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_POLYGON_BIT);

  glMatrixMode   (GL_MODELVIEW);
  glPushMatrix   ();
  glLoadIdentity ();

  glMatrixMode   (GL_PROJECTION);
  glPushMatrix   ();
  glLoadIdentity ();

#define g_Window states->window

#if 0 // Is this still the case (OS X)? It is not on Win32...
  /* XXX: For whatever reason, this does not work without first querying the viewport!!! */
  GLint viewport [4];
  glGetIntegerv (GL_VIEWPORT, viewport);
#endif

  glOrtho (0, g_Window->viewport.Width (), 0, g_Window->viewport.Height (), -1.0f, 1.0f);

  glFrontFace (GL_CCW);

  glDisable    (GL_DEPTH_TEST);
  glDepthMask  (GL_FALSE);
  //glDepthMask (GL_TRUE);

  glDisable   (GL_LIGHTING);
  glEnable    (GL_COLOR_MATERIAL);

  glEnable    (GL_ALPHA_TEST);
  glAlphaFunc (GL_NOTEQUAL, 0.0f);

  glEnable    (GL_BLEND);
  glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

  getTex ()->Enable ();
  getTex ()->Apply  (Epsilon3D::Texture::TexUnit0);

  glPushClientAttrib (GL_CLIENT_VERTEX_ARRAY_BIT);

  glEnableClientState  (GL_VERTEX_ARRAY);
  glEnableClientState  (GL_TEXTURE_COORD_ARRAY);
  glDisableClientState (GL_COLOR_ARRAY);

  glVertexPointer   (3, GL_FLOAT, sizeof (GlyphVertex), &verts [0].pos);
  glTexCoordPointer (2, GL_FLOAT, sizeof (GlyphVertex), &verts [0].st);

  glDrawElements (GL_TRIANGLES, idx_count, GL_UNSIGNED_SHORT, &indices[0]);

  glPopClientAttrib ();

  glMatrixMode (GL_PROJECTION);
  glPopMatrix  ();

  glMatrixMode (GL_MODELVIEW);
  glPopMatrix  ();

  glPopAttrib  ();

  //unprojector.End ();

  return x;
}




void
AddVertexEx (GlyphVertexEx& vert, int num, std::vector <GlyphVertexEx>& verts, int incr = 4)
{
  if (verts.size () <= num) {
    verts.resize (verts.size () + incr);
    //verts_size += incr;
  }

  verts [num] = vert;
}

void
AddIndexEx (unsigned short idx, int num, std::vector <unsigned short>& indices, int incr = 6)
{
  if (indices.size () <= num) {
    indices.resize (indices.size () + incr);
    //indices_size += incr;
  }

  indices [num] = idx;
}

float
eFont::PrintToArray ( const TCHAR* string,
                      float        x,
                      float        y,
                      DWORD        rgba,
                      int&                          last_vert,
                      std::vector <GlyphVertexEx>&  verts,
                      std::vector <unsigned short>& indices,
                      float                         scale )
{
  // In OpenGL, we draw from the bottom up, so find the BOTTOM Y coordinate...
  y -= (GetRowHeight () * 1.25f);

  int num_tris = 0;

  TCHAR c = *string;

  if (c > maxChar)
    c = _T (' ');    // prevent array overruns

  //unsigned short vtx_count = 0;
  unsigned int   idx_count = (last_vert / 4) * 6;

  while (c != 0) {
    eGlyphTexRect&   r  = glyphs_ [c].rect;
    eGlyphTexCoords& st = glyphs_ [c].st;

    GlyphVertexEx vert;

    /* These two statements uncommented on 5/27/2011 - Fixes Win32... */
    vert.pos   [2] = 0.0f;
    vert.pos   [3] = 1.0f;

    *((DWORD *)vert.color) = rgba;

    vert.pos [0] = x + r.x;
    vert.pos [1] = y + r.y;
    vert.st  [0] = st.min.u;
    vert.st  [1] = st.min.v;

    AddVertexEx (vert, last_vert, verts);

    vert.pos [0] = x + r.x;
    vert.pos [1] = y + r.y - (r.h * scale);
    vert.st  [0] = st.min.u;
    vert.st  [1] = st.max.v;

    AddVertexEx (vert, last_vert + 1, verts);

    vert.pos [0] = x + (r.w * scale) + r.x;
    vert.pos [1] = y + r.y           - (r.h * scale);
    vert.st  [0] = st.max.u;
    vert.st  [1] = st.max.v;

    AddVertexEx (vert, last_vert + 2, verts);

    vert.pos [0] = x + (r.w * scale) + r.x;
    vert.pos [1] = y + r.y;
    vert.st  [0] = st.max.u;
    vert.st  [1] = st.min.v;

    AddVertexEx (vert, last_vert + 3, verts);


    /*
    icache->Resize (icache->GetSize () + 6);

    icache->SetIndex (last_idx, last_vtx + 0);
    icache->SetIndex (last_idx, last_vtx + 1);
    icache->SetIndex (last_idx, last_vtx + 2);
    icache->SetIndex (last_idx, last_vtx + 0);
    icache->SetIndex (last_idx, last_vtx + 2);
    icache->SetIndex (last_idx, last_vtx + 3);
    */

////    indices.push_back (0); indices.push_back (1); indices.push_back (2);
////    indices.push_back (0); indices.push_back (2); indices.push_back (3);

    AddIndexEx (last_vert + 0, idx_count++, indices);
    AddIndexEx (last_vert + 1, idx_count++, indices);  /* Triangle #1 */
    AddIndexEx (last_vert + 2, idx_count++, indices);

    AddIndexEx (last_vert + 0, idx_count++, indices);
    AddIndexEx (last_vert + 2, idx_count++, indices);  /* Triangle #2 */
    AddIndexEx (last_vert + 3, idx_count++, indices);

    last_vert += 4;
    num_tris  += 2;

    x += glyphs_ [c].advance;

    string++;
    c = *string;

    if (c > maxChar)
      c = _T (' ');    // prevent array overruns
  }

  return x;
}

void
eFont::FinishArrayPrint ( int                           num_verts,
                          std::vector <GlyphVertexEx>&  verts,
                          std::vector <unsigned short>& indices )
{
  glPushAttrib   (GL_TRANSFORM_BIT | GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_POLYGON_BIT);

  glMatrixMode   (GL_MODELVIEW);
  glPushMatrix   ();
  glLoadIdentity ();

  glMatrixMode   (GL_PROJECTION);
  glPushMatrix   ();
  glLoadIdentity ();

#define g_Window states->window

#if 0 // Is this still the case (OS X)? It is not on Win32...
  /* XXX: For whatever reason, this does not work without first querying the viewport!!! */
  GLint viewport [4];
  glGetIntegerv (GL_VIEWPORT, viewport);
#endif

  glOrtho (0, g_Window->viewport.Width (), 0, g_Window->viewport.Height (), -1.0f, 1.0f);

  glFrontFace (GL_CCW);

  glDisable   (GL_DEPTH_TEST);
  glDepthMask (GL_TRUE);

  glDisable (GL_LIGHTING);
  glEnable  (GL_COLOR_MATERIAL);

  glEnable    (GL_ALPHA_TEST);
  glAlphaFunc (GL_NOTEQUAL, 0.0f);

  glEnable    (GL_BLEND);
  glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

  getTex ()->Enable ();
  getTex ()->Apply  (Epsilon3D::Texture::TexUnit0);

  // This may be redundant, but better safe than sorry for now...
#if 1
  glPixelStorei   (GL_UNPACK_ALIGNMENT, 1);
  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
#endif

  glPushClientAttrib (GL_CLIENT_VERTEX_ARRAY_BIT);

  glEnableClientState (GL_VERTEX_ARRAY);
  glEnableClientState (GL_TEXTURE_COORD_ARRAY);
  glEnableClientState (GL_COLOR_ARRAY);

  glVertexPointer   (3, GL_FLOAT, sizeof (GlyphVertexEx), &verts [0].pos);
  glTexCoordPointer (2, GL_FLOAT, sizeof (GlyphVertexEx), &verts [0].st);
  glColorPointer    (4, GL_UNSIGNED_BYTE, sizeof (GlyphVertexEx), &verts [0].color);

  glDrawElements (GL_TRIANGLES, (num_verts / 4) * 6, GL_UNSIGNED_SHORT, &indices [0]);

  glPopClientAttrib ();

  glMatrixMode (GL_PROJECTION);
  glPopMatrix  ();

  glMatrixMode (GL_MODELVIEW);
  glPopMatrix  ();

  glPopAttrib  ();

  //unprojector.End ();
}


void
eFont::logPrintf (const TCHAR* szFormat, ...)
{
  va_list argv;

  if (szFormat == NULL)
    return;

  // Open the log file, if needed.
  openFontsLog ();

  /* Could not open log file, screw it! */
  if (_log == NULL)
    return; /* TODO: More sophisticated logic here... */


  va_start (argv, szFormat);
    _vftprintf (_log, szFormat, argv);
  va_end (argv);

  fflush (_log);
}

// logID is the logID for the font to be created
void
eFont::logFontCreation (const eFontInfo* fi, int logID)
{
  logPrintf (_T ("Attempting to create: %s, Point size: %d, Italics: %s, Bold: %s, FontID: %i\n"),
    fi->szName, fi->glyphSize, (fi->isItalic ? _T ("Yes") : _T ("No")), (fi->isBold ? _T ("Yes") : _T ("No")), logID);
}


// calling this multiple times will not crash it
void
eFont::logFontDestruction (const eFont* font)
{
  logPrintf (_T ("Destroying font with fontID: %i\n"), font->logFileID);
}


void
eFont::openFontsLog (void)
{
  // Create log file if needed
  if (_log == NULL) {
    _log = _tfopen (FONTS_LOG_FILE, _T ("w"));
  }
}

void
eFont::closeFontsLog (void)
{
  if (_log != NULL) {
    fclose (_log);
    _log = NULL;
  }
}


void
TexSubImage (int   dst_width,
             int   xOffset,   int    yOffset,
             int   src_width, int    src_height,
             byte* dst,        byte* src)
{
  for (int i = 0; i < src_height; i++) {
    byte* out = &dst [((yOffset + i) * dst_width) + xOffset];
    byte* in  = &src [(i * src_width)];

    for (int j = 0; j < src_width; j++) {
      *out++ = *in++;
    }
  }
}

static bool
SaveTGAFile ( const TCHAR*         filename,
              const short int&     width,
              const short int&     height,
              const unsigned char& bits,
              unsigned char*       imageData )
{
  unsigned char Unused000;  // Garbage collector (1-byte)
  short int     Unused001;  // Garbage collector (2-bytes)
  unsigned char imageType;  // Type of image we're writing
  int           colorMode;  // Color mode
  unsigned char colorSwap;  // Swap buffer
  int           imageIndex; // Index ID
  unsigned char bitDepth;   // Bit depth
  long          imageSize;  // Image data size
  FILE*         fTGA;       // Image file

  // Create our image
  if (! (fTGA = _tfopen (filename, _T ("wbS"))))
  {
    fclose (fTGA);
    return false;
  }

  switch (bits) {
    case 32:
      imageType = 3;  /* RGBA (BGRA) - Uncompressed */
      bitDepth  = 32;
      colorMode = 4;  /* 32-Bit RGBA */
      break;
    default:
    case 24:
      imageType = 2;  /* RGB (BGR) - Uncompressed */
      bitDepth  = 24;
      colorMode = 3;  /* 24-Bit RGB */
      break;
    case 16:
      imageType = 2;  /* RGB (BGR) - Uncompressed */
      bitDepth  = 16;
      colorMode = 2;  /* 16-Bit RGB */
      break;
  }

  Unused000 = NULL; // Garbage!
  Unused001 = NULL; // Garbage!

  // Write garbage (No Extra Header, No Compression)
  fwrite (&Unused000, sizeof (unsigned char),  1, fTGA);
  fwrite (&Unused000, sizeof (unsigned char),  1, fTGA);

  // Write imageType
  fwrite (&imageType, sizeof (unsigned char),  1, fTGA);

  // Write more garbage (No Compression)
  fwrite (&Unused001, sizeof (short int),      1, fTGA);
  fwrite (&Unused001, sizeof (short int),      1, fTGA);
  fwrite (&Unused000, sizeof (unsigned char),  1, fTGA);
  fwrite (&Unused001, sizeof (short int),      1, fTGA);
  fwrite (&Unused001, sizeof (short int),      1, fTGA);

  // Write image dimensions
  fwrite (&width,    sizeof (short int),       1, fTGA);
  fwrite (&height,   sizeof (short int),       1, fTGA);
  fwrite (&bitDepth, sizeof (unsigned char),   1, fTGA);

  // Write more garbage (No Flags)
  fwrite (&Unused000, sizeof (unsigned char),  1, fTGA);

  // Calculate image size
  imageSize = width * height * colorMode;

  // Change image data from RGB to BGR
  for (imageIndex = 0; imageIndex < imageSize; imageIndex += colorMode)
  {
    colorSwap = imageData [imageIndex];
    imageData [imageIndex]     = imageData [imageIndex + 2];
    imageData [imageIndex + 2] = colorSwap;
  }

  // Write the image data
  fwrite (imageData, sizeof (unsigned char), imageSize, fTGA);

  // Close the file
  fclose (fTGA);

  return true;
}

void
DumpGlyphs (const TCHAR* szFont, int pitch, int width, int height, byte* data)
{
  // 24-bpp TGA version of the 8-bit data stored in `data'.
  byte* pGlyphPageTGA = new byte [width * height * 3];

  for (int i = 0; i < (width * height); i++) {
    pGlyphPageTGA [ i * 3]      = data [i];
    pGlyphPageTGA [(i * 3) + 1] = data [i];
    pGlyphPageTGA [(i * 3) + 2] = data [i];
    //pGlyphPageTGA [(i * 3) + 3] = data [i];
  }

  extern void swap_scanlines (unsigned char* data, int width, int height, int bpp);
  swap_scanlines (pGlyphPageTGA, width, height, 3);

  TCHAR szName [MAX_PATH];
  _sntprintf (szName, MAX_PATH, _T ("Glyphs-%s_%d.tga"), szFont, pitch);

  SaveTGAFile (szName, width, height, 24, pGlyphPageTGA);

  delete [] pGlyphPageTGA;
}


#include "ft2build.h"
#include <freetype/freetype.h>  // FT_FREETYPE_H - this was causing problems when rebuilding sometimes

// returns true on success, faceSize is the size of the EM square in pixels
bool
eFont::loadFont (const eFontInfo* fi)
{
  // Free existing font if one is already loaded
  if (texture_ != NULL)
    Free ();

  info_ = *fi;
  info_.szName = strdup (fi->szName);

  // Log the creation of this font
  static int logID = 0;
  logFontCreation (fi, logID);
  logFileID = logID++;

  // These are the max & min ASCII values to load
  minChar = MIN_LOADED_CHAR;
  maxChar = MAX_LOADED_CHAR;


//  this->minChar = minChar;
//  this->maxChar = maxChar;

  // Truncate the log file if this is the first time, else append
  //  Was originally using a static ofstream here, but the <fstream> object allocates static
  //  memory and this memory was creating a huge spam of false memory leak reports.
  static bool firstTime = true;
  FILE * fp;
  if (firstTime) {
    fp = fopen("ft2fonts.log", "w");
    firstTime = false;
  }
  else
    fp = fopen("ft2fonts.log", "a");

  fprintf(fp, "Attempting to load: %s, Point size: %d\n", fi->szName, fi->glyphSize);

  // Create and initialize the Freetype2 library
  FT_Library library;

  int error = FT_Init_FreeType( &library );
  if (error) {
    // ... an error occurred during library initialization ...
    Assert(0, "Error initializing font library")    // TODO - UL error code?
    fprintf(fp, " Error: Unable to intialize font library\n");
    fclose(fp);
    return false;
  }

  int try_num = 0;

  // Append the default font path...
  char szPath [MAX_PATH];
  snprintf (szPath, MAX_PATH, "/Library/Fonts/%s", fi->szName);

TRY:
  // create the font face and load it in
  FT_Face face;
  error = FT_New_Face( library,
    szPath,                         // name of the file, eg "C:/fonts/arial.ttf"
    0,                              // load the first face in the file... there can be more than one
    &face );                        // the new face object
  if ( error == FT_Err_Unknown_File_Format ) {
    // ... the font file could be opened and read, but it appears that its font format is unsupported
    Assert(0, "Unknown face format")
    fprintf(fp, " Error: Unsupported font format\n");
    fclose(fp);
    FT_Done_FreeType(library);
    return false;
  }
  else if ( error ) {
    if (! try_num) {
      /* Try the current working directory if there is no font in the
           standard location(s). */
      snprintf (szPath, MAX_PATH, "%s", fi->szName);
//      snprintf (szPath, MAX_PATH, "/System/Library/Fonts/%s", fi->szName);
      try_num++;
      goto TRY;
    }

    // Another error code means that the font file could not be opened
    //  or read, or simply that it is broken...
    Assert(0, "Unable to load font")
    fprintf(fp, " Error: Can't read font file, error code - %d\n", error);
    fclose(fp);
    FT_Done_FreeType(library);
    return false;
  }

  // output some useful debugging information
  fprintf(fp, " %d glyphs found.\n Font face is ", (int)face->num_glyphs);
  if ( !(FT_IS_SCALABLE(face)) )
    fprintf(fp, "NOT ");
  fprintf(fp, "scalable.\n %s contains %d bitmap strikes.\n", fi->szName, face->num_fixed_sizes);

  // attempt to set the face size
  error = FT_Set_Pixel_Sizes(face, 0, fi->glyphSize);
  if (error!=0) {
    Assert  (0, "Unable to set face size")

    fprintf (fp, " Error: Unable to set face size - for non-scalable fonts size may not supported.\n");
    fclose  (fp);

    FT_Done_Face     (face);
    FT_Done_FreeType (library);

    return false;
  }

  glyphs_ = new eGlyph [maxChar + 1];
  memset (glyphs_, 0, sizeof (eGlyph) * (maxChar + 1));

  int maxTextureSize = MAX_TEX_RES;

//  float totalWidth = 0.0f;
//  float maxHeight  = 0.0f;
  int   totalWidth = 0;
  int   maxHeight  = 0;
  int   numPasses  = 1;      // number of horizontal passes across texture

  int maxAscent, maxDescent;
  bitmap_width_ = bitmap_height_ = maxAscent = maxDescent = 0;

  FT_GlyphSlot slot = face->glyph;

  int c;
  for (c = minChar; c <= maxChar; c++) {
    error = FT_Load_Char (face, c, FT_LOAD_RENDER);
    if (error) {
      fprintf (fp, " Error : Unable to create AA bitmap for char - %d\n", c);
      continue; // Ignore errors
    }

    glyphs_ [c].advance =  (float)(slot->advance.x >> 6);
    glyphs_ [c].rect.SetX ((slot->bitmap_left));
    glyphs_ [c].rect.SetY ((slot->bitmap_top)); // XXX: Ignore, for some reason ...    Negative because we're going up from baseline

    int width = (slot->bitmap.width);
    if (totalWidth + width >= maxTextureSize)
      numPasses++;

    totalWidth += width;

    glyphs_ [c].rect.SetWidth (width);

    int height = (slot->bitmap.rows);
    if (height > maxHeight)
      maxHeight = height;

    glyphs_ [c].rect.SetHeight (height);

//    eTB_Printf ("Glyph (%c) - (%d x %d)\n", c, width, height);
  }

  // Use 'T' and 'g' to estimate the ascent and descent heights
  ascent    = -glyphs_ ['T'].rect.GetY ();
  descent   =  glyphs_ ['g'].rect.GetY () + glyphs_ ['g'].rect.GetHeight ();
  rowHeight = ascent + descent + 2;  // Leave 2 empty spaces above and below the line

  // Find the needed texture size
  //  Work out the width. Most likely maxTextSize
  int textureWidth = maxTextureSize;

  if (numPasses == 1) {
    textureWidth = eNextPowerOf2 ((unsigned int)totalWidth);
    Assert (textureWidth <= maxTextureSize, "textureWidth is larger than maxTextureSize while loading fonts...");
  }

  int textureHeight = eNextPowerOf2 ((unsigned int)(numPasses * maxHeight));
      textureHeight = (textureHeight > maxTextureSize) ? maxTextureSize : textureHeight;

  // Allocate some memory and clear it to transparent
  int totalMem = textureWidth * textureHeight;
  unsigned char* texMem = new unsigned char [totalMem]; // GL_ALPHA texture
  memset (texMem, 0, totalMem);

  if (states->cl_verbose)
    eTB_Printf ("New Font Texture: (%d x %d)\n", textureWidth, textureHeight);

  /// Allocate Texture
  /// Bind Texture

  int xOffset = 0;
  int yOffset = 0;

  for (c = minChar; c <= maxChar; c++)
  {
    // Load glyph image into the slot (erase previous one) and convert to bitmap
    error = FT_Load_Char (face, c, FT_LOAD_RENDER);
    if (error) {
      fprintf (fp, " Error: Unable to create AA bitmapf or char - %d - pass 2.\n", c);
      continue; // ignore errors
    }

    // Wrap as Necessary
    int width = (slot->bitmap.width);
    if (xOffset >= (textureWidth - width)) {
      xOffset = 0;
      yOffset += maxHeight;

      if (yOffset > (textureHeight - maxHeight)) {
        fprintf (fp, " Error: Texture size too small!\n");
        fclose (fp);
        Assert (0, "Texture size too small");
        Free ();
        FT_Done_Face (face);
        FT_Done_FreeType (library);
        return false;
      }
    }

    FT_Bitmap* source = &(slot->bitmap);

    int destWidth  = source->width;
    int destHeight = source->rows;

    if (destWidth && destHeight) {
      TexSubImage (textureWidth, xOffset, yOffset, destWidth, destHeight, texMem, source->buffer);
    }

    // Texture Co-Ords
    glyphs_ [c].st.min.u = (float)xOffset / (float)textureWidth;
    glyphs_ [c].st.min.v = (float)yOffset / (float)textureHeight;
    glyphs_ [c].st.max.u = (float)(xOffset + destWidth) / (float)textureWidth;
    glyphs_ [c].st.max.v = (float)(yOffset + destHeight) / (float)textureHeight;

    xOffset += width;
  } // End for (Each Charater)

  DumpGlyphs (fi->szName, fi->glyphSize, textureWidth, textureHeight, texMem);

  /*
  // load in the advances, sizes and offsets in the first pass so we can
  //  calculate the needed texture size.
  advances = new float[maxChar+1];
  rects = new cFontRectangle[maxChar+1];
  uv = new cTexCoord[maxChar+1];
  memset(advances, 0, sizeof(float)*(maxChar+1));
  int maxTextureSize;
  glGetIntegerv( GL_MAX_TEXTURE_SIZE, (GLint*)&maxTextureSize);
  float totalWidth = 0.0f;
  float maxHeight = 0.0f;
  int numPasses = 1;
  FT_GlyphSlot slot = face->glyph;  // a small shortcut
  int c;
  for (c = minChar; c <= maxChar; c++ ) {
    // load glyph image into the slot (erase previous one) and convert to bitmap
    error = FT_Load_Char( face, c, FT_LOAD_RENDER );
    if (error) {
      fprintf(fp, " Error: Unable to create AA bitmap for char - %d\n", c);
      continue;  // ignore errors
    }

    advances[c] = (float)(slot->advance.x >> 6);
    rects[c].SetX( float(slot->bitmap_left) );
    rects[c].SetY( -float(slot->bitmap_top) );   // negative because we're going up from baseline
    float width = float(slot->bitmap.width);
    if (totalWidth + width >= maxTextureSize)
      numPasses++;
    totalWidth += width;
    rects[c].SetWidth( width );
    float height = float(slot->bitmap.rows);
    if (height > maxHeight)
      maxHeight = height;
    rects[c].SetHeight( height );
  }

  // Use 'T' and 'g' to estimate the ascent & descent heights
  ascent = -rects['T'].GetY();
  descent = rects['g'].GetY() + rects['g'].GetHeight();
  rowHeight = ascent + descent + 2;   // leave 2 empty spaces above and below the line

  // find the needed texture size
  // work out the max width. Most likely maxTextSize
  int textureWidth = maxTextureSize;
  if (numPasses == 1) {
    textureWidth = eNextPowerOf2( (unsigned int)totalWidth );
    Assert(textureWidth <= maxTextureSize, "textureWidth is larger than maxTextureSize while loading fonts")
  }
  int textureHeight = eNextPowerOf2( (unsigned int)(numPasses*maxHeight) );
  textureHeight = (textureHeight > maxTextureSize) ? maxTextureSize : textureHeight;

  // allocate some mem and clear it to transparent
  int totalMem = textureWidth * textureHeight;
  unsigned char * texMem = new unsigned char[totalMem]; // GL_ALPHA texture;
  memset(texMem, 0, totalMem);

  // Create the blank texture
  glGenTextures( 1, &texID);
  glPixelStorei( GL_UNPACK_ALIGNMENT, 1);
  glBindTexture( GL_TEXTURE_2D, texID);
  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  glTexImage2D( GL_TEXTURE_2D, 0, GL_ALPHA, textureWidth, textureHeight, 0, GL_ALPHA, GL_UNSIGNED_BYTE, texMem);

  delete [] texMem;

  fprintf(fp, " Using a %dx%d texture to store the font - texture memory: %d bytes.\n",
    textureWidth, textureHeight, textureWidth*textureHeight);

  // render the glyphs into the texture using glTexSubImage2D()
  float xOffset = 0.0f;
  float yOffset = 0.0f;
//  glBindTexture( GL_TEXTURE_2D, texID);
  for (c = minChar; c <= maxChar; c++ ) {
    // load glyph image into the slot (erase previous one) and convert to bitmap
    error = FT_Load_Char(face, c, FT_LOAD_RENDER );
    if (error) {
      fprintf(fp, " Error: Unable to create AA bitmap for char - %d - pass 2.\n", c);
      continue;  // ignore errors
    }

    // wrap as necessary
    float width = float(slot->bitmap.width);
    if( xOffset >= ( textureWidth - width)) {
      xOffset = 0.0f;
      yOffset += maxHeight;
      if( yOffset > (textureHeight - maxHeight)) {
        fprintf(fp, " Error: Texture size too small!\n");
        fclose(fp);
        Assert(0, "Texture size too small")
        Free();
        FT_Done_Face(face);
        FT_Done_FreeType(library);
        return false;
      }
    }

    FT_Bitmap * source = &(slot->bitmap);

    int destWidth = source->width;
    int destHeight = source->rows;

    if( destWidth && destHeight) {
      glTexSubImage2D( GL_TEXTURE_2D, 0, (int)xOffset, (int)yOffset, destWidth,
        destHeight, GL_ALPHA, GL_UNSIGNED_BYTE, source->buffer);
    }

    //      0
    //      +----+
    //      |    |
    //      |    |
    //      |    |
    //      +----+
    //           1
    // Texture co-ords
    uv[c].UL.x = xOffset / float(textureWidth);
    uv[c].UL.y = yOffset / float(textureHeight);
    uv[c].BR.x = (xOffset + (float)destWidth) / float(textureWidth);
    uv[c].BR.y = (yOffset + (float)destHeight) / float(textureHeight);

    xOffset += width;
  } // end for (each character)
*/

  // free the face object
  if ((error = FT_Done_Face (face)) != 0) {
    fprintf (fp, " Unable to destroy font face.\n");
    fclose  (fp);

    Free ();

    FT_Done_FreeType (library);

    return false;
  }
  else
    fprintf (fp, " Font face successfully released\n");

  // shutdown the freetype2 library
  error = FT_Done_FreeType (library);

  if (error != 0) {
    fprintf (fp, " Unable to free font library\n");
    fclose  (fp);

    Free();

    return false;
  }

  else
   fprintf (fp, " Font library successfully released\n");

  fprintf (fp, "Load successful.\n\n");
  fclose  (fp);

  byte* rgbaTexMem = new byte [textureWidth * textureHeight * 4];
  for (int i = 0; i < (textureWidth * textureHeight); i++) {
    rgbaTexMem [(i * 4)]     = texMem [i];
    rgbaTexMem [(i * 4) + 1] = texMem [i];
    rgbaTexMem [(i * 4) + 2] = texMem [i];

    if (texMem [i] == 0)
      rgbaTexMem [(i * 4) + 3] = 0;
    else
      rgbaTexMem [(i * 4) + 3] = 255;
  }

  eImage img (textureWidth, textureHeight, Epsilon::Image::Formats::RGBA, 4, rgbaTexMem, true);
  texture_ = states->window->rc->CreateTexture2D (&img, true);

  glPixelStorei   (GL_UNPACK_ALIGNMENT, 1);
  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

  delete [] texMem;

  return true;
}


/*
  OLD code - merged into Font class - delete eventually

bool cMemoryFont::Load(cFontInfo * fi) {
  struct black_box_t {  
    int x, y, w, h;  // bounding box for a character (x,y are offsets of top left corner from origin)
  };

  // free existing font if one is already loaded 
  if ( MemoryFontIsLoaded() )
    Free(); /// TODO

  // create log file
  static firstTime = true;
  FILE * fp;
  if (firstTime) {
    fp = fopen(MEMORY_FONTS_LOG, "w");
    firstTime = false;
  }
  else
    fp = fopen(MEMORY_FONTS_LOG, "a");
  fprintf(fp, "Attempting to create: %s, Point size: %d, Italics: %s, Bold: %s\n", 
    fi->fontname, fi->faceSize, (fi->isItalic?"Yes":"No"), (fi->isBold?"Yes":"No"));

  // Round number of grey shades to a value that GetGlyphOutline takes
  uint antiAliasingQuality;
  int numGreyShades = fi->numGreyShades;
  if (numGreyShades<=1) {
    antiAliasingQuality = GGO_BITMAP;       // 1 alpha value
    numGreyShades = 1;
  }
  else if (numGreyShades<=10) {
    antiAliasingQuality = GGO_GRAY2_BITMAP; // 4 alpha values
    numGreyShades = 4;
  }
  else if (numGreyShades<=30) {
    antiAliasingQuality = GGO_GRAY4_BITMAP; // 16 alpha values
    numGreyShades = 16;
  }
  else {
    antiAliasingQuality = GGO_GRAY8_BITMAP; // 64 alpha values
    numGreyShades = 64;
  }

  fprintf(fp, " Using %d alpha values to render font (%d requested).\n", 
    numGreyShades, fi->numGreyShades);

  minChar = fi->minChar;
  maxChar = fi->maxChar;

 	HFONT hFont;
	HFONT hOldFont;

	// default mapping mode is MM_TEXT. One logical unit = one pixel
  SetMapMode(fi->hDC, MM_TEXT);		// make sure we're in 1-1 coordinates

	hFont = Aont(fi->faceSize,		// height of font in pixels
							 0,		// avg character width, zero -> lets windows calculate	
							 0,		// angle of escapement
							 0,		// base-line orientation angle
               fi->isBold?FW_BOLD:FW_NORMAL,	// weight of the font (0-900)
               fi->isItalic?TRUE:FALSE,		    // italic on/off
							 FALSE,		// underline on/off
							 FALSE,		// strikeout on/off
							 ANSI_CHARSET,		// character set to use, international support
							 OUT_TT_PRECIS,	// use true type fonts whenever possible
							 CLIP_DEFAULT_PRECIS,	// set clipping precision
							 ANTIALIASED_QUALITY,	// quality of the font
							 FF_DONTCARE | DEFAULT_PITCH,		// pitch and family of the fonts
							 fi->fontname);	// typeface name of hte font
	if (!hFont) {
		Assert(0, "Font creation failure")
    fprintf(fp, " Error: Windows could not create the requested font.\n");
    fclose(fp);
		return false;
	}

	hOldFont = (HFONT)SelectObject(fi->hDC, hFont);
	
  // load in the advances, sizes and offsets in the first pass so we can
  //  calculate the needed texture size.
  black_box_t * rects = new black_box_t[maxChar+1];

  advances = new float[maxChar+1];
  memset(advances, 0, sizeof(float)*(maxChar+1));

  charOffsets = new int[maxChar+1];
  memset(charOffsets, 0, sizeof(int)*(maxChar+1));

  int maxAscent, maxDescent;
  texWidth = texHeight = maxAscent = maxDescent = 0;

  // required matrix for GetGlyphOutline() - use identity
  MAT2 mat2;
  memset(&mat2, 0, sizeof(MAT2));
  mat2.eM11.value = 1;
  mat2.eM12.value = 0;
  mat2.eM21.value = 0;
  mat2.eM22.value = 1;

  GLYPHMETRICS gm;

  // cycle through all the glyphs and determine their sizes and the ascent/descent
  // for the font.
  int c;
  for (c = minChar; c <= maxChar; c++ ) {
    int error = GetGlyphOutline(     // GetGlyphOutlineW for unicode?
      fi->hDC,     // handle to DC
      c,           // character to query
      antiAliasingQuality, // data format - this was GGO_METRICS - there seems to
        // be a bug in GetGlyphOutline().  It doesn't get the correct width sometimes
        // if you use GGO_METRICS.  eg. 16 pixel high arial in italics, capital 'A' and 
        // a few other letters also.
      &gm,         // glyph metrics
      0,        // size of data buffer
      0,    // data buffer
      &mat2        // transformation matrix
    );
    if (GDI_ERROR==error) {
      Assert(0, "Error loading glyph")
      fprintf(fp, " Error: Unable to get metrics for char - %d\n", c);
      continue;
    }

    Assert(gm.gmCellIncX>0, "non-positive advance")
    Assert(gm.gmBlackBoxX>0, "zero width char")
    Assert(gm.gmBlackBoxY>0, "zero height char")

    advances[c] = float(gm.gmCellIncX);
    texWidth += gm.gmCellIncX;
    rects[c].x = gm.gmptGlyphOrigin.x;

    // Sometimes gmptGlyphOrigin.x is negative, like for 't' or 'j' in 12 point Arial and you actually
    // have to backup one pixel and overwrite part of the previous character.  We can do this when working
    // with characters as tiny quads, but when working entire string textures there's a lot of special cases
    // to handle.  For example, we need to make sure we don't backup before the beginning of the texture, we
    // need to make sure we OR the overlapping pixels, and we need to have another array to allow to store the
    // backups.  
    //
    // Its just too complicated -- for now, we when encounter a character that requires a backup, we just shift
    // the character to the right by the amount of space we were supposed to back it up, so really, its not
    // getting backed-up at all.  Note that we are still allowing characters that have positive rects[c].x, which
    // get shifted forward.
    if (rects[c].x < 0) {
      advances[c] -= rects[c].x;   // we need extra space on the right hand side of the char, cause we're shifting it right
      rects[c].x = 0;
    }

    int characterAscent = gm.gmptGlyphOrigin.y;
    rects[c].y = characterAscent; 
    if ( characterAscent > maxAscent)
      maxAscent = characterAscent;
    rects[c].w = gm.gmBlackBoxX;
    int height = gm.gmBlackBoxY;
    if (height > texHeight)
      texHeight = height;
    rects[c].h = height;
    if (maxDescent < height - characterAscent)
      maxDescent = height - characterAscent;
  }

  // store float version
  ascent = maxAscent;
  descent = maxDescent;

  // TODO - this bothers me... the size of the space bbox for arial 16 pt font is 1x1 and 
  //  the pixel is turned on in bitmapped mode.  This causes a little dot everywhere where
  //  a space should go... didn't investigate with other fonts.
  rects[_T(' ')].w = 0;
  rects[_T(' ')].h = 0;

  texHeight = ascent + descent;
  rowSpacing = ascent + descent + 2;   // leave an empty space above and below the line

  for (c=minChar; c<=maxChar; c++)
    charOffsets[c] = charOffsets[c-1] + int(advances[c-1])*texHeight;

  // allocate some mem for the texture and clear it to transparent
  int texSize = texHeight*texWidth;
  texMemory = new unsigned char[texSize];   // alpha texture;
  memset(texMemory, 0, texSize);

  //
  // Render the glyphs into the memory texture
  //

  uchar charBuff[4096];    // temporary storage for characters
  for (c = minChar; c <= maxChar; c++ ) {
    // Get the needed buffer size
    int buffSize = GetGlyphOutline(     // GetGlyphOutlineW for unicode?
      fi->hDC,     // handle to DC
      c,           // character to query
      antiAliasingQuality,  // number of shades of alpha
      &gm,         // glyph metrics
      0,           // size of data buffer
      0,           // data buffer
      &mat2        // transformation matrix
    );
    if (buffSize==GDI_ERROR) {
      Assert(0, "Error determining glyph buffer size")
      fprintf(fp, " Error: Unable to determine buffer size for char - %d\n", c);
      continue;
    }

   // If GGO_BITMAP is specified, characters are loaded in in DWORD aligned rows.  
   // So, for example, if your character is only one bit wide (eg.'!') and 11 bits
   //  high, then only the first bit of each of 11 sucessive DWORDs is used.

   // create the actual bitmaps
   int error = GetGlyphOutline(     // GetGlyphOutlineW for unicode?
      fi->hDC,     // handle to DC
      c,           // character to query
      antiAliasingQuality,  // number of shades of alpha
      &gm,         // glyph metrics
      buffSize,    // size of data buffer
      charBuff,    // data buffer
      &mat2        // transformation matrix
    );
    if (error==GDI_ERROR) {
      Assert(0, "Error loading glyph")
      fprintf(fp, " Error: Unable to create gridfitted glyph for char - %d\n", c);
      continue;
    }

    float destWidth = rects[c].w;
    float destHeight = rects[c].h;

    //
    // charOffsets[c] will point to the top line of pixels that is part of the character 'c'.
    //  Each subsequent line of pixels follows.
    //

    uchar * writeRowPtr = memoryTex + charOffsets[c] + rects[c].x + (maxAscent - rects[c].y)*int(advances[c]);
    uchar * writePtr = writeRowPtr;  

    // rescale and repack the data given by windows into UNSIGNED_BYTE format
    if (numGreyShades==1) {
      // convert the bit array to a byte array
      uchar * readPtr = charBuff;  
      uchar * nextLinePtr = charBuff+4;
      int col = 0;
      int row = 0;
      while (row < destHeight) {
        uchar ch = *readPtr;   // current character
        while (col < destWidth) {
          uchar mask = 0x1 << (7 - col%8);
          if (ch & mask)
            *(writePtr++) = 255;
          else
            *(writePtr++) = 0;
          col++;
          if (col%8==0)
            ch = *(++readPtr);
        }
        // skip to next dword aligned row
        col %= 32;
        if (col!=0)   // if col==0, we're already at the beginning of a new dword
          readPtr += 4 - col/8;   // else jump the read ptr to the next dword
        col = 0;
        row++;
        writeRowPtr += int(advances[c]);
        writePtr = writeRowPtr;
      }
    }
    else {
      // scale to unsigned bytes 0..255, instead of 0..numGreyShades-1
      uchar * readPtr = charBuff;
      float scaleFactor = 255.0f / float(numGreyShades);
      int col = 0;
      int row = 0;
      while (row < destHeight) {
        while (col < destWidth) {
          // scale to 0..255 alpha
          *writePtr = (int)(float(*readPtr) * scaleFactor);
          writePtr++;
          readPtr++;
          col++;
        }
        // skip to next dword aligned row
        col %= 4;
        if (col!=0)   // if col==0, we're already at the beginning of a new dword
          readPtr += 4 - col;   // else jump the read ptr to the next dword
        col = 0;
        row++;
        writeRowPtr += int(advances[c]);
        writePtr = writeRowPtr;
      }
    }
    
  } // end for (each character)

  delete [] rects;

	SelectObject(fi->hDC, hOldFont);
	DeleteObject(hFont);

  fprintf(fp, "Load successful.\n\n");
  fclose(fp);

  return true;
}
*/







/*
      char szOut [MAX_PATH];
      if (isalnum (glyph_num + 1)) {
        if (isupper (glyph_num + 1))
          snprintf (szOut, MAX_PATH, "Font (%C).tga", glyph_num + 1);
        else
          snprintf (szOut, MAX_PATH, "Font (%C-).tga", glyph_num + 1);
      } else
        snprintf (szOut, MAX_PATH, "Font (0x%02x).tga", glyph_num + 1);

      byte* expand = new byte [(int)destWidth * (int)destHeight * 4];

      for (int i = 0; i < ((int)destWidth * (int)destHeight); i++) {
        expand [ i * 4]      = source [i];
        expand [(i * 4) + 1] = source [i];
        expand [(i * 4) + 2] = source [i];
        expand [(i * 4) + 3] = source [i];
      }

      extern void swap_scanlines (unsigned char* data, int width, int height);
      swap_scanlines (expand, (int)destWidth, (int)destHeight);

      SaveTGAFile (szOut, (int)destWidth, (int)destHeight, 32, expand);

      delete [] expand;
*/





void
eFont::Free (void)
{
  logFontDestruction (this);

  delete [] glyphs_;
  glyphs_ = NULL;

  delete [] bitmap_;
  bitmap_ = NULL;

  if (texture_ != NULL) {
    delete texture_;
    texture_ = NULL;

    // TODO: Do we have a method to make sure the texture is not bound after
    //         it is deleted?
  }

  if (info_.szName != NULL) {
    delete [] info_.szName;
    info_.szName = NULL;
  }
}